﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;

namespace Twi.DataAccess.Common
{
    public abstract class TwiCommand : IDisposable
    {
        /// <summary>
        /// 表示要对数据源执行的 SQL 语句或存储过程。 
        /// 为表示命令的、数据库特有的类提供一个基类。 
        /// Overload:System.Data.Common.DbCommand.ExecuteNonQueryAsync
        /// </summary>
        public DbCommand _cmd = null;

        /// <summary>
        /// 执行完成是否自动提交事务
        /// </summary>
        public bool IsAutoSubmitTran { get; set; }

        public DbUtility _DB { get; set; }
        /// <summary>
        /// DbConnection 初始化，DbConnection打开，
        /// DbCommand初始化，设置执行命令等待时间,默认是 300秒
        /// </summary>
        public void Initialize(DbUtility db)
        {
            _DB = db;
            DbConnection conn = _DB.providerFactory.CreateConnection();
            conn.ConnectionString = _DB.ConnectionString;
            conn.Open();
            _cmd = conn.CreateCommand();
            _cmd.CommandTimeout = 300;
        }

        public void Initialize(DbUtility db, DbCommand cmd)
        {
            _DB = db;
            _cmd = cmd;
        }

        public void Initialize(DbUtility db, DbConnection conn, DbTransaction txn)
        {
            _DB = db;
            _cmd = conn.CreateCommand();
            _cmd.Transaction = txn;
        }

        /// <summary>
        /// 创建DbCommand
        /// </summary>
        /// <param name="conn"></param>
        public DbCommand CreateCommand()
        {
            DbCommand dbCmd = _cmd.Connection.CreateCommand();
            return dbCmd;
        }

        /// <summary>
        /// 获得Command创建的事物对象
        /// </summary>
        public DbTransaction Transaction
        {
            get
            {
                return _cmd.Transaction;
            }
        }

        /// <summary>
        /// 获得Command创建的事物对象
        /// </summary>
        /// <param name="isAutoSubmit"></param>
        /// <returns></returns>
        public DbTransaction BeginTransaction(bool isAutoSubmit = true)
        {
            this.IsAutoSubmitTran = isAutoSubmit;
            if (_cmd.Transaction == null)
            {
                DbTransaction tran = _cmd.Connection.BeginTransaction();
                if (_cmd is SqlCommand)
                {
                    _cmd.Transaction = tran;
                }
                return tran;
            }
            else
                return _cmd.Transaction;

        }

        /// <summary>
        /// 获得查询列表
        /// </summary>
        /// <param name="tableName">节点名称</param>
        /// <returns></returns>
        public abstract XElement GetMultiple(string tableName = "Item");

        /// <summary>
        /// 获得查询列表(分页)
        /// </summary>
        /// <param name="masterTableName"></param>
        /// <param name="sql"></param>
        /// <param name="searchCondition"></param>
        /// <param name="otherText"></param>
        /// <param name="pageSize"></param>
        /// <param name="pageIndex"></param>
        /// <returns></returns>
        public abstract XElement[] GetMultiple(string masterTableName, string sql, string searchCondition, string otherText, int pageSize, int pageIndex);

        /// <summary>
        /// 获得数据(分页/或不分页)
        /// </summary>
        /// <param name="masterTableName"></param>
        /// <param name="tablesSource"></param>
        /// <param name="searchCondition"></param>
        /// <param name="selectColumns"></param>
        /// <param name="orderExpression"></param>
        /// <param name="xePage"></param>
        /// <param name="subSearchCondition"></param>
        /// <param name="subOrderExpression"></param>
        /// <returns></returns>
        public abstract XElement[] GetMultiple(string masterTableName, string tablesSource, string searchCondition, string selectColumns, string orderExpression
            , XElement xePage, string subSearchCondition = "", string subOrderExpression = "");

        /// <summary>
        /// 获得单条数据
        /// </summary>
        /// <param name="tableName"></param>
        /// <returns>查询到记录返回，没有找到记录抛出异常</returns>
        public abstract XElement GetSingle(string tableName = "Item");

        public abstract XElement GetSingleOrEmpty(string tableName = "Item");

        /// <summary>
        /// 获得单条数据
        /// </summary>
        /// <param name="tableName"></param>
        /// <returns>查询到记录返回，没有找到记录返回null</returns>
        public abstract XElement GetSingleOrDefault(string tableName = "Item");

        /// <summary>
        /// 更新记录
        /// </summary>
        /// <param name="xe"></param>
        /// <param name="tableName"></param>
        /// <returns></returns>
        public abstract int ExecuteUpdate(XElement xe, string tableName = null);

        /// <summary>
        /// 新增记录，返回新增记录的ID
        /// </summary>
        /// <param name="xe"></param>
        /// <param name="tableName"></param>
        /// <returns></returns>
        public abstract object ExecuteInsert(XElement xe, string tableName = null);

        /// <summary>
        /// 获得数据库当前时间
        /// </summary>
        /// <returns></returns>
        public abstract DateTime GetCurrentDate();

        /// <summary>
        /// 添加参数
        /// </summary>
        /// <param name="name">参数名</param>
        /// <param name="value">参数值</param>
        public abstract void AddParameter(string name, object value);

        public void AddParameter(XElement xe)
        {
            AddParameter(xe.Name.LocalName, xe.Value);
        }


        public void SetParameter(XElement xe)
        {
            SetParameter(xe.Name.LocalName, xe.Value);
        }

        /// <summary>
        /// 设置参数值(参数存在设置值，不存在添加参数)
        /// </summary>
        /// <param name="name">参数名</param>
        /// <param name="value">参数值</param>
        public abstract void SetParameter(string paraName, object paraValue);

        /// <summary>
        /// 设置参数值(参数存在设置值，不存在添加参数)
        /// </summary>
        /// <param name="parameter">参数</param>
        public abstract void SetParameter(DbParameter parameter);

        /// <summary>
        /// 设置参数并返回当前参数
        /// </summary>
        /// <param name="paraName"></param>
        /// <param name="type"></param>
        /// <param name="size"></param>
        /// <returns></returns>
        public abstract DbParameter SetParameter_InputOutput(string paraName, TwiDbType type, int size = 0);

        /// <summary>
        /// 初始化 DbParameter 类的新实例。
        /// </summary>
        /// <returns>返回 SqlParameter或OracleParameter 实例</returns>
        protected abstract DbParameter CreateDbParameter();

        /// <summary>
        /// 对连接对象执行 SQL 语句。
        /// </summary>
        /// <returns>受影响的行数。</returns>
        public abstract int ExecuteNonQuery();

        /// <summary>
        /// 执行查询，并返回查询所返回的结果集中第一行的第一列。 所有其他的列和行将被忽略。
        /// </summary>
        /// <returns>结果集中第一行的第一列。</returns>
        public abstract object ExecuteScalar();


        /// <summary>
        /// 执行查询，返回DbDataReader
        /// </summary>
        /// <returns></returns>
        public abstract DbDataReader ExecuteReader();

        /// <summary>
        /// 获取 DbParameterCollection。
        /// 返回结果:Transact-SQL 语句或存储过程的参数。 默认值为空集合。
        /// </summary>
        public abstract DbParameterCollection Parameters { get; }

        /// <summary>
        /// 连接字符串
        /// </summary>
        /// <param name="separartor"></param>
        /// <param name="format"></param>
        /// <returns></returns>
        public abstract string GetConcatenate(string separartor, string format = "{0}");

        #region override DbCommand
        /// <summary>
        /// 获取或设置命令结果在由 System.Data.Common.DbDataAdapter 的 Update 方法使用时如何应用于 System.Data.DataRow。
        /// 返回结果:System.Data.UpdateRowSource 值之一。 如果该命令不是自动生成的，则默认值为 Both。 否则，默认值为 None。
        /// </summary>
        public UpdateRowSource UpdatedRowSource
        {
            get
            {
                return _cmd.UpdatedRowSource;
            }
            set
            {
                _cmd.UpdatedRowSource = value;
            }
        }

        /// <summary>
        /// 获取或设置一个值，该值指示此命令对象在自定义界面控件中是否可见。
        /// 返回结果:如果该命令对象应在控件中可见，则为 true；否则为 false。 默认值为 true。
        /// </summary>
        public bool DesignTimeVisible
        {
            get
            {
                return _cmd.DesignTimeVisible;
            }
            set
            {
                _cmd.DesignTimeVisible = value;
            }
        }

        /// <summary>
        /// 获取或设置将在其中执行此 System.Data.Common.DbCommand 对象的 System.Data.Common.DbCommand.DbTransaction。
        /// 返回结果:要在其中执行 .NET Framework 数据提供程序的 Command 对象的事务。 默认值为 null 引用（在 Visual Basic中为 Nothing）。
        /// </summary>
        protected DbTransaction DbTransaction
        {
            get
            {
                return _cmd.Transaction;
            }
            set
            {
                _cmd.Transaction = value;
            }
        }

        /// <summary>
        /// 获取或设置此 System.Data.Common.DbCommand 使用的 System.Data.Common.DbConnection。
        /// 返回结果:与数据源的连接。
        /// </summary>
        public DbConnection DbConnection
        {
            get
            {
                return _cmd.Connection;
            }
            set
            {
                _cmd.Connection = value;
            }
        }

        /// <summary>
        /// 指示或指定如何解释 System.Data.Common.DbCommand.CommandText 属性。
        /// 返回结果：System.Data.CommandType 值之一。 默认值为 Text。
        /// </summary>
        public CommandType CommandType
        {
            get
            {
                return _cmd.CommandType;
            }
            set
            {
                _cmd.CommandType = value;
            }
        }

        /// <summary>
        /// 获取或设置针对数据源运行的文本命令。
        /// </summary>
        public string CommandText
        {
            get
            {
                return _cmd.CommandText;
            }
            set
            {
                _cmd.CommandText = value;
            }
        }

        /// <summary>
        /// 等待命令执行的时间（以秒为单位）。默认值为 30 秒。
        /// 返回结果：要执行的文本命令。 默认值为空字符串 ("")。
        /// </summary>
        public int CommandTimeout
        {
            get
            {
                return _cmd.CommandTimeout;
            }
            set
            {
                _cmd.CommandTimeout = value;
            }
        }

        /// <summary>
        /// 针对 System.Data.Common.DbCommand.Connection 执行 System.Data.Common.DbCommand.CommandText，并使用
        /// System.Data.CommandBehavior 值之一返回 System.Data.Common.DbDataReader。
        /// </summary>
        /// <param name="behavior">System.Data.CommandBehavior 值之一。</param>
        /// <returns>System.Data.Common.DbDataReader 对象。</returns>
        protected DbDataReader ExecuteDbDataReader(CommandBehavior behavior)
        {
            return _cmd.ExecuteReader(behavior);
        }

        public virtual DataTable ExecuteDatatable()
        {
            DataTable dt = new DataTable();
            DbDataAdapter adpt = _DB.CreateDataAdapter();
            adpt.SelectCommand = _cmd;
            adpt.Fill(dt);
            return dt;
        }

        /// <summary>
        /// 在数据源上创建该命令的准备好的（或已编译的）版本。
        /// </summary>
        public void Prepare()
        {
            _cmd.Prepare();
        }

        /// <summary>
        /// 尝试取消 System.Data.Common.DbCommand 的执行。
        /// </summary>
        public void Cancel()
        {
            _cmd.Cancel();
        }

        public void Dispose()
        {
            _cmd.Dispose();
        }
        #endregion

    }
}
